// api/ragApi.ts

/**
 * RAG 系统 API 封装
 * 统一管理前端与 Python 后端（FastAPI）的交互。
 */

import { initializeApiConfig } from './config';
const API_BASE = initializeApiConfig(); 

// --- 类型定义 (与后端数据结构保持一致) ---
export interface RagConfig {
  // 提示词模板 (Prompt Templates)
  qa_prompt_template: string;
  title_prompt_template: string;
  general_chat_prompt_template: string;

  // 召回与重排参数 (Retrieval & Reranking)
  retrieval_top_k: number;
  initial_retrieval_multiplier: number;
  history_retrieval_top_k: number;
  use_reranker: boolean;
  reranker_type: 'local' | 'llm' | string;

  // 文本分割参数 (Chunking)
  chunk_method: 'fixed_size' | 'semantic' | string;
  chunk_size: number;
  chunk_overlap: number;

  // 语义切分参数 (Semantic Chunking)
  semantic_buffer_size: number;
  semantic_threshold: number; // 0-100

  // LLM & 系统参数 (System Params)
  llm_max_context_tokens: number;
  llm_max_retries: number;
  retry_base_delay: number;
  
  // 引用相似度阈值 (Citation)
  citation_similarity_threshold: number; // 0.0-1.0
}

interface QueryResponse {
  answer: string;
  sources: string[]; // 文件名列表
}

interface ErrorDetail {
  detail: string;
}

// --- 辅助函数：处理 API 响应和错误 ---
async function handleResponse<T>(response: Response): Promise<T> {
  if (!response.ok) {
    let errorDetail: ErrorDetail = { detail: '未知 API 错误' };
    try {
      errorDetail = await response.json();
    } catch (e) {
      // 无法解析 JSON 的非 2xx 响应（例如 500 HTML 错误）
      const text = await response.text();
      errorDetail.detail = response.statusText + ': ' + text.substring(0, 100) + '...';
    }
    throw new Error(errorDetail.detail);
  }
  return response.json();
}


/**
 * 清理 ChromaDB Collection
 * DELETE /api/v1/chromadb/clear
 */
export const clearChromaDB = async (): Promise<{ message: string }> => { // <--- 关键：确保这里有 export
  const response = await fetch(`${API_BASE}/chromadb/clear`, {
    method: 'DELETE',
  });

  // 假设后端返回一个简单的成功消息 { message: "..." }
  return handleResponse(response);
};


/**
 * 获取当前的 RAG 配置
 * GET /api/v1/config/rag
 * 注意：此函数需要将后端返回的 snake_case 转换为前端的 camelCase。
 * 由于 RagConfig 字段过多，我们改为接收并返回 snake_case (或直接使用后端数据结构)
 * 为简化前端模型，我们在前端仍使用 camelCase，但在 API 转换。
 */
export const getRagConfig = async (): Promise<RagConfig> => {
  const response = await fetch(`${API_BASE}/config/rag`);
  const data = await handleResponse<any>(response);
  
  // 仅转换需要交互的字段，其余字段保持原样（假设它们就是 snake_case）
  return {
    ...data, // 假设大部分字段名保持一致，直接解构
    // retrieval_top_k -> retrievalTopK (如果你在前端用了这个命名，但后端是 snake_case)
    retrieval_top_k: data.retrieval_top_k, 
    initial_retrieval_multiplier: data.initial_retrieval_multiplier,
    // ... 实际项目可能需要大量映射，这里假设前端直接使用 snake_case 键名以简化
  } as RagConfig;
};

/**
 * 更新 RAG 配置
 * POST /api/v1/config/rag
 */
export const updateRagConfig = async (updates: Partial<RagConfig>): Promise<RagConfig> => {
  // 将前端的 camelCase (如果有) 转换为后端期望的 snake_case，然后发送
  const payload = {
    // 假设更新时直接发送完整的或部分的 RagConfig 键值对，无需复杂转换
    ...updates
  };

  const response = await fetch(`${API_BASE}/config/rag`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  const data = await handleResponse<any>(response);
  // 同样，返回时直接映射，并假设前端在 reactive 中会处理 snake_case 
  return data as RagConfig;
};